package wsepForum.domain.handlers;

import java.util.Collection;
import java.util.Vector;

import wsepForum.common.elements.Message;
import wsepForum.common.elements.Section;
import wsepForum.common.elements.SectionHeader;
import wsepForum.common.elements.User;
import wsepForum.common.elements.AForumElement.ForumElementType;
import wsepForum.domain.SessionManager;
import wsepForum.domain.exceptions.SystemFailureException;
import wsepForum.domain.exceptions.UnAuthorizedException;
import wsepForum.logging.ForumLogger;
import wsepForum.persistance.IPersistentHandler;
import wsepForum.persistance.exceptions.DataBaseIOException;
import wsepForum.persistance.exceptions.InvalidElementFormatException;
import wsepForum.persistance.exceptions.WrongElementIDException;
import wsepForum.persistance.exceptions.WrongUserNameException;

/**
 * The main interface between the GUI layer and the domain layer.
 * Provides the transportation of information between the GUI and the persistent.
 * Each further inheritance implements/overrides the services a certain user group
 * can receive from the system.
 *
 * This handler deals with an admin user
 *
 * @author Amir Harel & Ariel Rozen & Oren Ben-Haim
 */
public class AdminHandler extends ModeratorHandler {

	/*****************************
	 * CONSTRUCTOR               *
	 *****************************/
	public AdminHandler(User user, IPersistentHandler persistent) {
		super(user, persistent);
	}

	/*****************************
	 * METHODS                   *
	 *****************************/

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.AUserHandler#createSection(int, java.lang.String, java.util.Collection)
	 */
	@Override
	public Section createSection(int parentSectionID, String sectionName, Collection<String> moderators) throws Exception {
		Section updatedParentSection = null;
		Section newSection = new Section(sectionName,parentSectionID);
		this.getPersistent().setForumElement(parentSectionID, ForumElementType.SECTION, newSection);
		if(moderators != null){
			for (String userName : moderators) {
				this.addModeratorToSection(newSection.getElementID(), userName);
			}
		}
		updatedParentSection = this.getSection(parentSectionID);
		
		ForumLogger.getInstance().info("Admin " + this.getUser().getUserName() + " created Section " + sectionName + " under " +
				updatedParentSection.getHeadLine() + " Section ", ForumLogger.LoggerCategory.DOMAIN);
		
		return updatedParentSection;
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.AUserHandler#addModeratorToSection(int, java.lang.String)
	 */
	@Override
	public Section addModeratorToSection(int sectionID, String userName) throws WrongUserNameException, WrongElementIDException,
					UnAuthorizedException, SystemFailureException {
		try {
			Section updatedSection = null;
			User moderator = null;
			updatedSection = this.getSection(sectionID);
			if(updatedSection.isSectionMod(userName)) throw new UnAuthorizedException();
			moderator = this.getPersistent().getUser(userName);

			switch (moderator.getUserType()) {
				case MEMBER:
				{
					moderator.setUserType(User.UserType.MODERATOR);
					SessionManager.getInstance().notifyUserChange(moderator.getUserName());
					ForumLogger.getInstance().info("Admin " + this.getUser().getUserName()+ " grant "
							+ moderator.getUserName() + " as moderator", ForumLogger.LoggerCategory.DOMAIN);
				}
				case MODERATOR:
				{
					moderator.addSection(sectionID);
					updatedSection.addSectionMod(userName);
					break;
				}
				case ADMIN:
					return updatedSection;
			}

			ForumLogger.getInstance().info("Admin " + this.getUser().getUserName() + " add " + userName + " as moderator to " +
					updatedSection.getHeadLine() + " Section ", ForumLogger.LoggerCategory.DOMAIN);

			this.getPersistent().setForumElement(updatedSection.getParentID(), ForumElementType.SECTION, updatedSection);
			this.getPersistent().setUser(moderator);
			this.getPersistent().setForumElement(updatedSection.getParentID(), ForumElementType.SECTION, updatedSection);
			updatedSection = this.getSection(sectionID);
			
			return updatedSection;
		} catch (DataBaseIOException e) {
			throw new SystemFailureException(e);
		} catch (InvalidElementFormatException e) {
			throw new SystemFailureException(e);
		}
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.AUserHandler#removeModerator(int, java.lang.String)
	 */
	@Override
	public Section removeModerator(int sectionID, String userName) throws WrongUserNameException, WrongElementIDException, SystemFailureException {

		try {
			Section updatedSection = this.getSection(sectionID);;
			User moderator = null;
			moderator = this.getPersistent().getUser(userName);
			if((moderator.getUserType().equals(User.UserType.MODERATOR))&&(moderator.hasSection(sectionID))){
				moderator.removeSection(sectionID);

				updatedSection.removeSectionMod(userName);

				ForumLogger.getInstance().info(moderator.getUserName() + " lost his Moderator privelige in " + updatedSection.getHeadLine()
						, ForumLogger.LoggerCategory.DOMAIN);

				if(moderator.getAllSections().isEmpty()){
					moderator.setUserType(User.UserType.MEMBER);
					ForumLogger.getInstance().info("Admin " + this.getUser().getUserName() + " disgrant " + moderator.getUserName() + " from his Moderator privelige and he is now a Member", ForumLogger.LoggerCategory.DOMAIN);
				}

				this.getPersistent().setUser(moderator);
				SessionManager.getInstance().notifyUserChange(moderator.getUserName());
				this.getPersistent().setForumElement(updatedSection.getParentID(), ForumElementType.SECTION ,updatedSection);
			}
			else {
				ForumLogger.getInstance().error("ERROR: trying to remove moderator from Section " + updatedSection.getHeadLine() +
						" but " + userName + " is not moderator or is not moderator of the requested section", ForumLogger.LoggerCategory.DOMAIN);
				throw new WrongUserNameException("trying to remove moderator from Section not his", userName);
			}
			return updatedSection;
		} catch (DataBaseIOException e) {
			throw new SystemFailureException(e);
		} catch (InvalidElementFormatException e) {
			throw new SystemFailureException(e);
		}
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.AUserHandler#removeSection(int)
	 */
	@Override
	public Section removeSection(int sectionID) throws Exception {
		Section deleted = null;
		Section parentSection = null;
		if(sectionID != ROOT_SECTION){
			deleted = (Section) this.getPersistent().getForumElement(sectionID, ForumElementType.SECTION);

			ForumLogger.getInstance().info(deleted.getHeadLine() + " Section is now being deleted", ForumLogger.LoggerCategory.DOMAIN);

			Vector<SectionHeader> secHeaders = deleted.getAllSectionHeaders();
			for (SectionHeader subSec : secHeaders) {
				this.removeSection(subSec.getElementID());
			}
			parentSection = this.getSection(deleted.getParentID());
			Vector<String> secMods = deleted.getAllSectionMods();
			for (String userName : secMods) {
				this.removeModerator(deleted.getElementID(), userName);
			}
			parentSection = (Section) this.getPersistent().getForumElement(deleted.getParentID(), ForumElementType.SECTION);

			parentSection = (Section)this.getPersistent().deleteForumElement(sectionID, ForumElementType.SECTION);
		}
		else{
			ForumLogger.getInstance().fatal("ERROR: trying to remove Root Section!", ForumLogger.LoggerCategory.DOMAIN);
			throw new UnAuthorizedException();
		}
		return parentSection;
	}

	/**
	 * An admin can always edit messages.
	 * @param messageToEdit The message to edit
	 * @return true, if allowed to edit the message
	 */
	@Override
	public boolean editMessageAuthentication(Message messageToEdit, int sectionID) {
		return true;
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.ModeratorHandler#deleteMessageAuthentication(wsepForum.common.elements.Message, int)
	 */
	@Override
	public boolean deleteMessageAuthentication(Message messageToDelete, int sectionID) {
		return true;
	}


	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.AUserHandler#deleteSectionAuthentication()
	 */
	@Override
	public boolean editSectionAuthentication() {
		return true;
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.MemberHandler#removeUserAuthentication(java.lang.String)
	 */
	@Override
	protected boolean removeUserAuthentication(String userName) throws Exception {
		return !userName.equals("admin");
	}
	
	@Override
	public Vector<String> getManagedUsernames() {
		return getAllUsernames();
	}

}
